#pragma once
#include <string>
#include <iostream>
#include <type_traits>

using namespace std;

inline constexpr int factorial(int x)
{
	return x > 1? x * factorial(x - 1) : 1;
}

//inline constexpr int myStrlen(const char* str)
//{
//	return (*str) ? myStrlen(str + 1) + 1 : 0;
//}
//
//inline constexpr int ToInt(char ch)
//{
//	return (ch == '1') ? 1 : 0;
//}
//inline constexpr int myPow(int x, int y)
//{
//	return y ? x * myPow(x, y - 1) : 1;
//}
//inline constexpr int step_for_decimal(char ch,int y)
//{
//	return ToInt(ch) * (y ? 2 * step_for_decimal(ch,y - 1) : 1);
//}
//
//inline constexpr int CharBinToInt(const char* x, int size, int sum)
//{
//	return   size>1? CharBinToInt(++x, size - 1, sum + step_for_decimal(*x, myStrlen(x) - 1)): sum;
//}
//
//inline constexpr int operator""_b(const char* x)
//{
//	 return myStrlen(x)-1 ? ToInt(x[0]) * myPow(2,myStrlen(x) - 1) + operator""_b(++x) : ToInt(x[0]);
//	//return ToInt(*x) * myPow(2, myStrlen(x) - 1) + (myStrlen(x) > 1?  operator""_b(++x) : 0);
//	// return myStrlen(x) > 1?(ToInt(*x) * myPow(2, myStrlen(++x)) + operator""_b(++x)) : ToInt(x[0]);
//	//return (To_Dec(*x, myStrlen(x) - 1) + (myStrlen(x) > 1 ? operator""_b(++x) : 0))
//	//return //CharBinToInt(x, myStrlen(x), step_for_decimal(*x, myStrlen(x) - 1));
//}

inline constexpr unsigned long long ToInt(const char* x, unsigned long long res)
{
	return (*x == '\0') ? res : ToInt(x + 1, (res << 1) | (*x - static_cast< unsigned long long>('0')));
}

inline constexpr unsigned long long operator""_b(const char* x)
{
	
	return ToInt(x,0);
}

//inline string/*constexpr int*/ my_2_Pow(unsigned long long x, string& str)
//{
//	
//	unsigned long long n = x / 2;
//	if (n >= 2) str = my_2_Pow(n, str); else str.push_back(n % 2 ? '1' : '0');
//	char m = (x % 2 ? '1' : '0');
//	str.push_back(m);
//	return str;
//}


inline /*constexpr*/ string operator""_toBinStr(unsigned long long x)
{
	string str = "0b";
	unsigned long long mask = /*static_cast<unsigned long long>(1)*/ 1LL << CHAR_BIT * sizeof(x) - 1;
	bool fl = false;
	while (mask)//for (int i = 0; i < CHAR_BIT * sizeof(x) - 1; i++)
	{
		if (mask & x) 
		{fl = true; break; }
		else
		{mask = mask >> 1; }
	}
	
	if (!fl)str.push_back('0');
	
	while (mask)
	{
		str.push_back(mask & x? '1':'0');
		mask = mask >> 1;
	}

	return str;//my_2_Pow(x, str);
}

template<typename T>
auto GetValue(const T& t) 
{
	if constexpr (is_pointer</*reove_reference*/T>::value) { return *t; }
	else { return t; }
}

template<typename Container>
inline void print_container(const Container& cont)
{
	auto it_b = begin(cont), it_end = end(cont);

	while (it_b != it_end)
	{
		std::cout << GetValue(*it_b) << " ";
		++it_b;
	}
	std::cout << std::endl;
}

template<typename T1, typename T2>
inline ostream& operator<<(ostream& os, const pair<const T1, T2>& T_p)
{
	os << endl << "firs: " << T_p.first << " second:" << T_p.second;
	return os;
}

template<typename Container>
inline auto Get_adapter_Value(const Container& cont)
{
	if constexpr (is_same<Container, queue<typename Container::value_type, typename Container::container_type>>::value)
	{
		return GetValue(cont.front());//queue<T> 
	}
	else
	{
		return GetValue(cont.top());//stack, priority_queue 
	}	
}

//stack, priority_queue
template<typename Container>
inline void print_adapter(Container cont)
{
	while (!cont.empty())
	{
		std::cout << Get_adapter_Value(cont) << " ";
		cont.pop();
	}
	std::cout << std::endl;
}

template<typename T1, typename T2>
inline auto addition(const T1& first, const T2& second)
{
	if constexpr (is_same<T1, vector<T2/*, typename T1::allocator_type*/>>::value)
	{
		vector<T2> tmp;
		transform(first.begin(), first.end(), back_inserter(tmp), [&](const auto& x) {return second + x; });
		return tmp;
	}
	else
	{
		/*decltype(first + second)*/ auto tmp = first + second;
		return tmp;
	}
}

template<typename T>
inline T constexpr Smth()
{
	if constexpr (is_same<T, int>::value) return 1;
	if constexpr (is_same<T, double>::value) return 2.2;
	if constexpr (is_same<T, string>::value) return "abc";
}